﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using Itenso.TimePeriod;
using LogManager.Base.Data;
using LogManager.ViewModels;
using LogManager.ViewModels.Filter;
using MvcContrib.Pagination;
using MvcContrib.UI.Grid;
using MvcContrib.Sorting;
using LogManager.Helpers;
using LogManager.Excel;
using LogManager.Base;

namespace LogManager.Controllers
{
    public class ErrorController : BaseController
    {
        private readonly IEventService _eventService;
        private readonly IEventTypeService _typeService;
        private readonly ILogService _logService;
        private readonly IServerService _serverService;

        /// <summary>
        /// Creates a new error controller
        /// </summary>
        /// <param name="eventService">Event service</param>
        /// <param name="typeService">Event type service</param>
        public ErrorController(IEventService eventService, IEventTypeService typeService,IServerService serverService, ILogService logService)
        {
            //Assign services
            _eventService = eventService;
            _typeService = typeService;
            _serverService = serverService;
            _logService = logService;
        }

        /// <summary>
        /// Overview over the last errors
        /// </summary>
        /// <returns>List of error events</returns>
        [HttpGet]
        public ActionResult Index()
        {
            var model = new ErrorIndexViewModel
                            {
                                ExceptionFilter = new ExceptionTypeFilterViewModel(),
                                SourceFilter = new EventSourceFilterViewModel()
                                                   {
                                                       ServerNames = GetServerNames(),
                                                       LogNames = GetLogNames(null)
                                                   }
                            };
            return View(model);
        }

        /// <summary>
        /// Download all error events
        /// </summary>
        /// <returns>Excel file with errors</returns>        
        public ExcelResult<IEvent> ListDownload(string fileName, GridSortOptions sortOptions, int datePage = 1)
        {
            //Load all events (no server get limit)
            var events = _eventService
                .GetEvents(new TimeRange(DatePager.FromDate(datePage), DatePager.ToDate(datePage)))
                .Filter(level: "Error")
                .OrderBy(sortOptions.Column, sortOptions.Direction)
                .All();

            //Create excel result
            var excel = new ExcelResult<IEvent>(events) { Title = fileName }
                .Columns(column =>
                {
                    column.For(e => e.ServerName);
                    column.For(e => e.LogName);
                    column.For(e => e.Type);
                    column.For(e => e.Level);
                    column.For(e => e.Message);
                    column.For(e => e.User);
                    column.For(e => e.TimeStamp);
                    column.For(e => e.Properties.GetValueOrDefault("ExceptionType", null)).Named("ExceptionType");
                    column.For(e => e.Properties.GetValueOrDefault("ExceptionDetail", null)).Named("ExceptionDetail ");
                    column.For(e => e.Properties.GetValueOrDefault("StackTraceFileName", null)).Named("StackTraceFileName ");
                    column.For(e => e.Properties.GetValueOrDefault("StackTraceFileLineNumber", null)).Named("StackTraceFileLineNumber");
                    column.For(e => e.Properties.GetValueOrDefault("RequestUrl", null)).Named("RequestUrl");
                    column.For(e => e.Properties.GetValueOrDefault("RequestPath", null)).Named("RequestPath ");
                    column.For(e => e.Properties.GetValueOrDefault("UserHostAddress", null)).Named("UserHostAddress");
                    column.For(e => e.Properties.GetValueOrDefault("IdentityName", null)).Named("IdentityName");
                });

            return excel;
        }

        /// <summary>
        /// Return the last errors
        /// </summary>
        /// <returns>List of error events</returns>
        public ActionResult List(GridSortOptions sortOptions,string serverName = null, string logName = null, string exception = null, int datePage = 1, int page = 1, int count = 20)
        {
            if (sortOptions.Column == null)
            {
                sortOptions.Column = "TimeStamp";
                sortOptions.Direction = SortDirection.Descending;
            }

            var events = _eventService
                .GetEvents(new TimeRange(DatePager.FromDate(datePage), DatePager.ToDate(datePage)))
                .Filter(level: "Error")
                .OrderBy(sortOptions.Column, sortOptions.Direction)
                .Filter(serverName: serverName, logName: logName)
                .Search("ExceptionType",exception)
                .AsPagination(page, count);

            var model = new EventList
                            {
                                Events = events,
                                DownloadUrl = Url.Action("ListDownload", "Error", new { fileName = "ErrorEvents_" + DateTime.Now.ToShortDateString().Replace('.', '_') + ".xls" }),
                                SortOptions = sortOptions,
                            };
            return PartialView(model);
        }

        /// <summary>
        /// Return events grouped by their request
        /// </summary>
        /// <returns>List of event requests</returns>
        public ActionResult Request()
        {
            return View();
        }

        /// <summary>
        /// List of events grouped by their request
        /// </summary>
        /// <param name="logName">Log name to filter</param>
        /// <param name="sortOptions">Sort options for the events</param>
        /// <param name="page">Pagenumber</param>
        /// <param name="count">Number of items per page</param>
        /// <returns>List of requests</returns>
        public ActionResult ListRequest(GridSortOptions sortOptions, string logName = null, int page = 1, int count = 20)
        {
            //Get projections
            var requests = _eventService.GetEventsPath();

            //Filter by log if set
            if(!string.IsNullOrEmpty(logName))
                requests = requests.Where(r => r.LogName == logName);

            //Create view model
            var model = new EventsPerPathList
            {
                Requests = requests
                    .OrderBy(sortOptions.Column, sortOptions.Direction)
                    .AsPagination(page, count),
                SortOptions = sortOptions,
            };

            return PartialView(model);
        }

        //public ActionResult Exceptions(string serverName,string logName)
        //{
        //    var exceptions = _eventService.GetEvents(new EventDateRange())
        //        .Filter(new EventSourceFilter(serverName, logName))
        //        .Filter(new EventTypeFilter("Error"))
        //        .GroupBy(e => e.Properties["ExceptionType"] as string)
        //        .Select(g => new ErrorViewModel
        //                         {
        //                             ExceptionType = g.Key,
        //                             Amount = g.Count(),
        //                             LastError = g.Max(e => e.TimeStamp)
        //                         })
        //        .ToList();
        //    return View(exceptions);
        //}


        public JsonResult EventsErrorStackedData(DateTime? start, DateTime? end)
        {
            var eventTypes = _eventService.GetEventsType();
            var categories = eventTypes.Select(t => t.Type).Distinct();

            var model = new
            {
                types = eventTypes
            };

            var series = new List<object>();
            

            //var model = new
            //                {
            //                    categories = logs.Select(l => l.LogName),
            //                    series = series
            //                };
            
            return Json(model, JsonRequestBehavior.AllowGet);
        }

        //private IQueryable<LogEventTypeJsonModel> GetEventTypes(ILog log, DateTime start, DateTime end)
        //{
        //    return log.Events.WithSimpleType().Query()
        //        .Where(e => e.Level == "Error" && e.TimeStamp > start && e.TimeStamp < end)
        //        .GroupBy(e => e.Type)
        //        .Select(g => new LogEventTypeJsonModel
        //                         {
        //                             LogName = log.LogName,
        //                             Type = g.Key,
        //                             Count = g.Count()
        //                         });
        //}


        /// <summary>
        /// Get all server names for dropdownlist
        /// </summary>
        /// <returns>List of server names</returns>
        private IEnumerable<string> GetServerNames()
        {
            var items = _serverService.All().Select(s => s.ServerName).ToList();
            items.Insert(0, "All");
            return items;
        }

        private IEnumerable<string> GetLogNames(string serverName)
        {
            var items = string.IsNullOrEmpty(serverName) ? new List<string>() : _logService.All(serverName).Select(l => l.LogName).ToList();
            items.Insert(0, "All");
            return items;
        }

        public ActionResult EventsDonut()
        {
            return View();
        }

    }
}
